import { hexToBytes } from '@noble/hashes/utils.js';
import { describe, should } from '@paulmillr/jsbt/test.js';
import { deepStrictEqual as eql, throws } from 'node:assert';
import { bn254 } from '../src/bn254.ts';
import { bytesToNumberBE } from '../src/utils.ts';
import { jsonGZ } from './utils.ts';
import { default as ethDump } from './vectors/bn254/eth-dump.js';
import { default as seda } from './vectors/bn254/seda.js';
const CROSS_PATH_GZ = './vectors/bn254/cross1000.json.gz'; // bundler hint: readFileSync('./test/bn254/cross1000.json.gz')

describe('bn254', () => {
  const { Fp2, Fp6, Fp12 } = bn254.fields;
  should('Fp2', () => {
    const x = {
      c0: 9175274256610746571769806138441460978067247223835479920885065774008687444157n,
      c1: 20773477212147349335400672939850062067877721538384265447234655811868542594493n,
    };
    const y = {
      c0: 18745010300259074081467171901089189864928626882998930881106784720284549917403n,
      c1: 6755404584462298611753346784665337222239198745905936344431516651379215797104n,
    };
    const mul = Fp2.mul(x, y);
    eql(mul, {
      c0: 14915367931151687313527782314310395056617474070176176799315072532155545111131n,
      c1: 21234748560869198098271980834340238051100753263426135951820710752881888827685n,
    });
    eql(Fp2.inv(mul), {
      c0: 14059357043488439067899523657279480228325398861171369736421103353153531444488n,
      c1: 10653662974983088626765328812465558213584029561070266019112600033405785100357n,
    });
    eql(Fp2.pow(mul, 123n), {
      c0: 10215561122296849292546524321406303162476266646558890975893280707450285855932n,
      c1: 4537324909364976254935527093258254296114714749851039294808365654432443471764n,
    });
    eql(Fp2.mulByNonresidue(mul), {
      c0: 0x07e037c032c72fca1ad3101fe7826263823ca54d39d091e6396a2919752311abn,
      c1: 0x13f9045c1b9e7f1ef3aa2daa5d59e7e7ca826cf63a9b4ce115e4ab8f34e4c529n,
    });
    eql(Fp2.frobeniusMap(mul, 0), {
      c0: 0x20f9cc90b32f1bf9d6b520a01b8a0c8074892df17aab86ba95305c9cf37b4a5bn,
      c1: 0x2ef27117b3e8ab2dd7f9b8f088d1544ca10ee3590bfe35e6d8a65bf8dfc19925n,
    });
    eql(Fp2.frobeniusMap(mul, 1), {
      c0: 0x20f9cc90b32f1bf9d6b520a01b8a0c8074892df17aab86ba95305c9cf37b4a5bn,
      c1: 0x0171dd5b2d48f4fbe0568cc5f8b00410f67287385c7394a6637a301df8bb6422n,
    });
    eql(Fp2.frobeniusMap(mul, 2), {
      c0: 0x20f9cc90b32f1bf9d6b520a01b8a0c8074892df17aab86ba95305c9cf37b4a5bn,
      c1: 0x2ef27117b3e8ab2dd7f9b8f088d1544ca10ee3590bfe35e6d8a65bf8dfc19925n,
    });
    eql(Fp2.frobeniusMap(mul, 3), {
      c0: 0x20f9cc90b32f1bf9d6b520a01b8a0c8074892df17aab86ba95305c9cf37b4a5bn,
      c1: 0x0171dd5b2d48f4fbe0568cc5f8b00410f67287385c7394a6637a301df8bb6422n,
    });
    // deepStrictEqual(Fp2.multiplyByB(mul), {});
    eql(Fp2.sqr(mul), {
      c0: 0x06be9f41936b73fee167d253de7f0e5b593907af77de4ee4719c2e867d0d2935n,
      c1: 0x2771aeff417616dd85e1c7ed0f32de184f1ad8824b5cbae7d1f75bebb82c5360n,
    });
    eql(
      Fp2.sqrt(
        Fp2.fromBigTuple([
          9539370033468661209380275700986402421887789242020002300585859967789873971892n,
          2408207196858065672509024269166317846107134392635521956359186237465509592685n,
        ])
      ),
      Fp2.fromBigTuple([
        11735470634387873799477049885533764022761384076526147647478746466286296399544n,
        13618633949391667835520719449938342187292725425802172484249840050686954616369n,
      ])
    );
    eql(
      Fp2.sqrt(
        Fp2.fromBigTuple([
          9539370033468661209380275700986402421887789242020002300585859967789873971892n,
          0n,
        ])
      ),
      Fp2.fromBigTuple([
        0n,
        11474336573315612962807055017310908889127934811628703059389981608666953233848n,
      ])
    );
    eql(Fp2.sqrt(Fp2.fromBigTuple([0n, 0n])), Fp2.fromBigTuple([0n, 0n]));
    throws(() =>
      Fp2.sqrt(
        Fp2.fromBigTuple([
          16212884381720205059738200348067889451048348728726328281994858199167930326546n,
          1962819860904253127057474190621175035877218611129096092768456880922435651200n,
        ])
      )
    );
    eql(
      Fp2.sqrt(
        Fp2.fromBigTuple([
          12352847319525355024456442719184913847134238145817530183012048714311776063934n,
          2878680128520940498385063749000100786444790337863374616277716932611683190222n,
        ])
      ),
      Fp2.fromBigTuple([
        21077761961308505487834328147025281384890763274646311107292782163765614166141n,
        12796536346553613569391598678213045373503765474828973069913340863975911801366n,
      ])
    );
  });
  should('Fp6', () => {
    const x = {
      c0: {
        c0: 14551901853310307118181117653102171756020286507151693083446930124375536995872n,
        c1: 9312135802322424742640599513015426415694425842442244572104764725304978020017n,
      },
      c1: {
        c0: 2008578374540014049115224515107136454624926345291695498760935593377832328658n,
        c1: 19401931167387470703307774451905975977586101231060812348184567722817888018105n,
      },
      c2: {
        c0: 15835061253582829097893482726334173316772697321004871665993836763948321578465n,
        c1: 2434436628082562384254182545550914004674636606111293955202388712261962820365n,
      },
    };
    const y = {
      c0: {
        c0: 2874440054453559166574356420729655370224872280550180463983603224123901706537n,
        c1: 21199736323249863378180814900160978651989782296293186487853700340281870105680n,
      },
      c1: {
        c0: 19165582755854282767090326095669835261356341739532443976394958023142879015770n,
        c1: 1381947898997178910398427566832118260186305708991760706544743699683050330259n,
      },
      c2: {
        c0: 282285618133171001983721596014922591835675934808772882476123488581876545578n,
        c1: 9533292755262567365755835323107174518472361243562718718917822947506880920117n,
      },
    };
    const mul = Fp6.mul(x, y);
    eql(
      mul,
      Fp6.fromBigSix([
        0x27e02cac09778f17790eca88049591eab8303bde8b0ce544812271ce663837f5n,
        0x199e2a26c8afc66867c44b24df5839e82d12f36049c3e64aa64cd7660b59367fn,
        0x209dc99f28838227cd70d7873882bfc02e906ae6b49a6763e2e4aaf40cca48cdn,
        0x237401e06589ded3b91d4ea9b6f0d38fb43bba4057e0f72c0ceddc6ce6de6084n,
        0x0b7cea190caaf555cda98bc428818e3f48b9eba82496ed8643f275464af2edadn,
        0x26b45ad7a7aaf40a62c2c33113bc6e992ff827df086bdb12a8903b67bbe87951n,
      ])
    );
    eql(
      Fp6.inv(mul),
      Fp6.fromBigSix([
        0x157cc42ef8b45c3083066eef83ba7fdb49a15109957430cf3193fbd25e738c20n,
        0x2fee15140b4848575d0bf9e59264d9e72ba7e7165b05ae79f2048538a72afd5fn,
        0x1cd0b2051602ad6ed01f1162ca3e17177c062ea343bf9858510c2d15a5ddeed1n,
        0x27f317f2c8ff95d58fd56a32c5f7ffe7fcb74249f31d9894b8bf8ed13d68e62en,
        0x13f8336ffc8a0058b8fa98d1a719893a32202a270a687a00d1fa8360d8966eccn,
        0x11c15de4d913051b97398c242d2b9ad3b3c1891e7a0a808077cd58cee3ac07a5n,
      ])
    );
    eql(
      Fp6.pow(mul, 123n),
      Fp6.fromBigSix([
        0x27fd73f942655006f23e15c8a72b85c85f89268cdd3f2c924fa97f51a600bcf1n,
        0x194878e948b9204d91b346524d30a99e7464bda2ef86344d041e30960fd215ben,
        0x1fd553a51dc52fa32053759e4601106c0bb92c8b1336dd233dec71b2b2d08240n,
        0x22c9771b70b8ee70a641dd7c9fbe4b7315561d31b379b770982fc65ec54bbca1n,
        0x0a8f183318dfe52d9cd8d7bd6e9b8322e154824fbfa94cb37a20882b90d73e9en,
        0x224204a78f3913b0442dbfbbf9e9a1c0a1383440c38f120fbf45cfc293debfc0n,
      ])
    );
    eql(
      Fp6.mulByNonresidue(mul),
      Fp6.fromBigSix([
        0x104b9196e9260bd01fe2e0fdd7503942c70fb678d870b4187ed557fa0e24e47dn,
        0x1515f689c952288f3c5080804f980712d3e96885954517518c20b74bfab44495n,
        0x27e02cac09778f17790eca88049591eab8303bde8b0ce544812271ce663837f5n,
        0x199e2a26c8afc66867c44b24df5839e82d12f36049c3e64aa64cd7660b59367fn,
        0x209dc99f28838227cd70d7873882bfc02e906ae6b49a6763e2e4aaf40cca48cdn,
        0x237401e06589ded3b91d4ea9b6f0d38fb43bba4057e0f72c0ceddc6ce6de6084n,
      ])
    );
    eql(
      Fp6.frobeniusMap(mul, 0),
      Fp6.fromBigSix([
        0x27e02cac09778f17790eca88049591eab8303bde8b0ce544812271ce663837f5n,
        0x199e2a26c8afc66867c44b24df5839e82d12f36049c3e64aa64cd7660b59367fn,
        0x209dc99f28838227cd70d7873882bfc02e906ae6b49a6763e2e4aaf40cca48cdn,
        0x237401e06589ded3b91d4ea9b6f0d38fb43bba4057e0f72c0ceddc6ce6de6084n,
        0x0b7cea190caaf555cda98bc428818e3f48b9eba82496ed8643f275464af2edadn,
        0x26b45ad7a7aaf40a62c2c33113bc6e992ff827df086bdb12a8903b67bbe87951n,
      ])
    );
    eql(
      Fp6.frobeniusMap(mul, 1),
      Fp6.fromBigSix([
        0x27e02cac09778f17790eca88049591eab8303bde8b0ce544812271ce663837f5n,
        0x16c6244c1881d9c1508bfa91a2291e756a6e77311eade44295d3b4b0cd23c6c8n,
        0x132e9042df94be5c8ed786bbcd98ac890cafc95345c39f72888caa55fa1ff081n,
        0x016a090a6ddf5ef16c119792e100a325e96d6e3adf447a5a774af621dc45e2c6n,
        0x015136acb9ff0f6c81e825b5d227baf690bba9674ec7674c30bd6bdd1047baa5n,
        0x0e4f2d75f9f41f72c312da70c678a41644a4a1afd64c134d85f7b67b27f9b209n,
      ])
    );
    eql(
      Fp6.frobeniusMap(mul, 2),
      Fp6.fromBigSix([
        0x27e02cac09778f17790eca88049591eab8303bde8b0ce544812271ce663837f5n,
        0x199e2a26c8afc66867c44b24df5839e82d12f36049c3e64aa64cd7660b59367fn,
        0x0c2e0fd60cb375902db8a5c2c33f4860e3611058e1cea66a94f3201406fc80ffn,
        0x2eb682f7a51ae78eb9c4996988e877d7657450e7fa11b8ae550ab37760b4b1f9n,
        0x29baff51841d03bcd7c5987868d9363a944bdda5629bbb797c868f5114efe5c9n,
        0x044986602e372645c816c426f065bcc197b4c3f1a5049216ffe14369a7d0cdd5n,
      ])
    );
    eql(
      Fp6.frobeniusMap(mul, 3),
      Fp6.fromBigSix([
        0x27e02cac09778f17790eca88049591eab8303bde8b0ce544812271ce663837f5n,
        0x16c6244c1881d9c1508bfa91a2291e756a6e77311eade44295d3b4b0cd23c6c8n,
        0x14cc3d058707177dc0dcb876f113f40134c6dcf0db2791f3d1142f252ec16816n,
        0x156f0cb47ec49b6c172163632e582bc6ad2739df2e2fea58279b925c70c01ecen,
        0x0aa1680b90efb6e8eb549574457a895e1b91069787def2230df36e5ccd4bb71dn,
        0x1e6a07e972f8d7a6f80815b3ae512237839afa29ec884122fd21bdc5d2e7c0f3n,
      ])
    );
    eql(
      Fp6.frobeniusMap(mul, 6),
      Fp6.fromBigSix([
        0x27e02cac09778f17790eca88049591eab8303bde8b0ce544812271ce663837f5n,
        0x199e2a26c8afc66867c44b24df5839e82d12f36049c3e64aa64cd7660b59367fn,
        0x209dc99f28838227cd70d7873882bfc02e906ae6b49a6763e2e4aaf40cca48cdn,
        0x237401e06589ded3b91d4ea9b6f0d38fb43bba4057e0f72c0ceddc6ce6de6084n,
        0x0b7cea190caaf555cda98bc428818e3f48b9eba82496ed8643f275464af2edadn,
        0x26b45ad7a7aaf40a62c2c33113bc6e992ff827df086bdb12a8903b67bbe87951n,
      ])
    );
    eql(
      Fp6.sqr(mul),
      Fp6.fromBigSix([
        0x15a40c8311cae8572c9729fc5a3e17ac6613a586d3a6e4771748db60f1b34c31n,
        0x1be5ada29b45980659cd74fd84dc0ee237266d6b49e26e3e3c75f5f7f8e36bb6n,
        0x0f37e1b5d6eaf8b29ed6539f41d572c8e4176a30022c0887b519451423132778n,
        0x11553deeefd057dba88269992c0bce481bd2d10e3171110270d1e65a5027b795n,
        0x15320d24d2f439519f5655e84e7de5ea51352ad042edc3507dc7f4cc8a58d60dn,
        0x0a22ae20afe73e947d5355b92ce82e9ce1d6a427444c0704ee38a5266b758bd2n,
      ])
    );
  });

  describe('Fp12', () => {
    should('Basic', () => {
      const x = Fp12.fromBigTwelve([
        14551901853310307118181117653102171756020286507151693083446930124375536995872n,
        9312135802322424742640599513015426415694425842442244572104764725304978020017n,
        2008578374540014049115224515107136454624926345291695498760935593377832328658n,
        19401931167387470703307774451905975977586101231060812348184567722817888018105n,
        15835061253582829097893482726334173316772697321004871665993836763948321578465n,
        2434436628082562384254182545550914004674636606111293955202388712261962820365n,
        2874440054453559166574356420729655370224872280550180463983603224123901706537n,
        21199736323249863378180814900160978651989782296293186487853700340281870105680n,
        19165582755854282767090326095669835261356341739532443976394958023142879015770n,
        1381947898997178910398427566832118260186305708991760706544743699683050330259n,
        282285618133171001983721596014922591835675934808772882476123488581876545578n,
        9533292755262567365755835323107174518472361243562718718917822947506880920117n,
      ]);
      const y = Fp12.fromBigTwelve([
        18047981096479337102146667749895076239629141801291955469384704565216104187314n,
        15666664160719503771597247415419223930649457344221068845696585378185259231782n,
        19104486138427766678685981088012332131195800219059514705455734667515973606461n,
        9981398918396711625955686259070817172664979929677830651988555105509994339171n,
        11896632435097590900354609446159654476372962698668471398580977554098318198563n,
        14221980458534454581231952169237170519081003872664907970911977130536153649527n,
        10342309967155150758354801395014075652225221643351782543638326396015198777712n,
        11621837078398424322606208174682557100993333529246445615493549022059226612768n,
        5236968339662193120507082558938968646636336333031399422938355946719863068135n,
        18078826069444667006861228825551021353661733895571187371353872321244928807011n,
        9227965260032410354414324195411397451806478640651098414622140162144550225774n,
        4565231055964369875954050676600907662092934946529352128407430527253758726453n,
      ]);
      const mul = Fp12.mul(x, y);
      eql(
        mul,
        Fp12.fromBigTwelve([
          0x1f7e1915f79c255833f7a13152cbde37e75c7477b0e9e43bd7682159c581eb59n,
          0x0b87ab9f76ec58d51764793075679db7ef021b6e9947588cdbfe718efe93313en,
          0x069cdaf8a1c617a3411205c2f79031bf765e5c223019ea81c7b30b979ae8a7a5n,
          0x284421e203ea9cd11d7e7c3bc4f6c0f6f2f0df6dea4f5f0e77532bf5db230190n,
          0x0cddcd1a97c14c06ac7066d8260433f49341d541de58cc5f0e9b77f2a44b6f75n,
          0x1c0740acf5fbc0dae7b89b70a340dd09535c6358cfcc30dbc8e50081d0766067n,
          0x0cf7e9c5f664bf3c4e805797034b637045be90a2e22dcbdc404d85aa1c4baee8n,
          0x126b7779bce9780813bff1692a361eaf4388727c737f9df8b7f98e4a709e7c96n,
          0x0c0a9578e9e41e5534610d675ddd5c98d49363016f3bb76d5ae15c083075e23bn,
          0x04443f45fbf2bbabb84645f9eb3e8ce39294cf2289abb9baabf7983a3b75adbbn,
          0x1f7797b3b1b3bc1b201b49d1e6d32a3114444f43bcd8cac719fbcef72d861449n,
          0x0aaa7b3a32f45da005612e5f1d642f4c3747672cb6e299260fc8ce90cc5a8a87n,
        ])
      );
      eql(
        Fp12.inv(mul),
        Fp12.fromBigTwelve([
          0x05744faaa44310060263cdfbf2b1bb1f515cf33d26d7ecc7107fe6a3ec251185n,
          0x2d54b17e46122f2b767610b0b26ab6915ec21ba016db5852305dba4d8cf25677n,
          0x27ae9cb3c3944d47dee334be37018d867eb5ee706e6ca431038183ff6cfff7a5n,
          0x302aaa3806cf037e41da5384e4e328047676c036a0c79f2da9149b372ae9a676n,
          0x204de4defcf5e5a4fb083006a53f19813b643227e845dfe4e1bc7d1d3ab0a948n,
          0x27b91d79207633f9d0a11b55f73b9bca81bf3dca09b11973c633dbf5b34560can,
          0x0c746b6793c042aa0df2bcdb5d3d2fa36273f924c281e837cffdfa71d9a490dcn,
          0x0da44ee23f6d5e42f8a08f5b8de3f539f3e17da1cb10fade34d3ceeb50a93fdcn,
          0x01441b37493be1047a38393ae6affa331ee64588dadfaca844919e2cff661036n,
          0x2f0c84d0afb414ad51feab583ec80db1cd060d926bf74b542a7620c34116591dn,
          0x1285fb560a154755531ff279d05b653e5e0392cf7ab3c5d61d27e6320bb7922fn,
          0x168261b17bc59996e80854efc14c13ed7a44e148d694de221ff5b6460a813391n,
        ])
      );
      eql(
        Fp12.pow(mul, 123n),
        Fp12.fromBigTwelve([
          0x1898158de89f46fc80741acd697ac74d54432740370a09042cf623af17f4ce47n,
          0x2979db09847736636829d40a9c6d498e934be77df1e950d4e5e11090c693570fn,
          0x18c242ed1969d064d2583b3534ad1c2cceb5d1a82e6a2339564f0cb020b460d5n,
          0x2ddc5b2f690058edb213ec055c840858bd3c62bf1a12fd727910c9cba160eeb6n,
          0x0b8948826ee6e0efe8f20ddc0dcda977b8e580c771bdd02d9178646855181437n,
          0x2516a5f6cd7479f88f1c5f67c4a2584eb47afa4e1abb923edccaab856bb5c585n,
          0x1c2fd565187876677d041e2f1c694e6b332d13459546dc97bff5d160c812ef4bn,
          0x1ab6251add526666d9342779eb7415c08a23ef9e920a67bcc47edd47099f4d8bn,
          0x27cb017ec84ee36111a75a8d2734d605824f79e5a150b21b2c24b9893223ec1dn,
          0x021673105d0dec60a9e0b7eca52b6c4b00b2de69a1abfddebec2eff279f08031n,
          0x14f3a1b2336880e9eae8998fdcda6589674ab644b558b7881edd80db4e999d12n,
          0x258f97869ce5267a507acec85e5ad2d0acf43ff00bad850c9a7e53541b55696an,
        ])
      );
      eql(
        Fp12.frobeniusMap(mul, 0),
        Fp12.fromBigTwelve([
          0x1f7e1915f79c255833f7a13152cbde37e75c7477b0e9e43bd7682159c581eb59n,
          0x0b87ab9f76ec58d51764793075679db7ef021b6e9947588cdbfe718efe93313en,
          0x069cdaf8a1c617a3411205c2f79031bf765e5c223019ea81c7b30b979ae8a7a5n,
          0x284421e203ea9cd11d7e7c3bc4f6c0f6f2f0df6dea4f5f0e77532bf5db230190n,
          0x0cddcd1a97c14c06ac7066d8260433f49341d541de58cc5f0e9b77f2a44b6f75n,
          0x1c0740acf5fbc0dae7b89b70a340dd09535c6358cfcc30dbc8e50081d0766067n,
          0x0cf7e9c5f664bf3c4e805797034b637045be90a2e22dcbdc404d85aa1c4baee8n,
          0x126b7779bce9780813bff1692a361eaf4388727c737f9df8b7f98e4a709e7c96n,
          0x0c0a9578e9e41e5534610d675ddd5c98d49363016f3bb76d5ae15c083075e23bn,
          0x04443f45fbf2bbabb84645f9eb3e8ce39294cf2289abb9baabf7983a3b75adbbn,
          0x1f7797b3b1b3bc1b201b49d1e6d32a3114444f43bcd8cac719fbcef72d861449n,
          0x0aaa7b3a32f45da005612e5f1d642f4c3747672cb6e299260fc8ce90cc5a8a87n,
        ])
      );
      eql(
        Fp12.frobeniusMap(mul, 1),
        Fp12.fromBigTwelve([
          0x1f7e1915f79c255833f7a13152cbde37e75c7477b0e9e43bd7682159c581eb59n,
          0x24dca2d36a454754a0ebcc860c19baa5a87f4f22cf2a720060221a87d9e9cc09n,
          0x25b85c5816cfae8bc0677bb4f0b6f637fc0c8b080a7798851d9b4b0da5471378n,
          0x01d78e434febfb5aa293d04da42b89aff9691a55ed45d8bb97ee8a6f86d354dan,
          0x298717b8c72936a7c7fdcdf5eb801c9f645871dcfa6464992a1cd700c886adben,
          0x1a2d8dcaca9827895eb89dd3862288812c8d3c035a6b538d7efc7db265f69229n,
          0x194a36115b892547f3ba56b1936e5fa87257a9810df2bf3ab87b153e8620d56fn,
          0x23e8d078d87f3325b5d3e2a2d2929ed03f998f9a7e6d5de454b3b962968f954cn,
          0x05d18e9ebd6c3d7f1fdd174e98cf9bc34ccae092e2bb6c6992b4c47d0b68fc2bn,
          0x2fc6153f206c381b2376aac5bf320ec5f215342f755aa6ed5c696c6b410acacan,
          0x287260b1cfb2e1b72aa804bf9b7c83c38df42c04784b980208394cde7698b34cn,
          0x04eab8c01c3f99d3706e0c1521791574304867d9a39cd35032316fdbcb3e4a61n,
        ])
      );
      eql(
        Fp12.frobeniusMap(mul, 2),
        Fp12.fromBigTwelve([
          0x1f7e1915f79c255833f7a13152cbde37e75c7477b0e9e43bd7682159c581eb59n,
          0x0b87ab9f76ec58d51764793075679db7ef021b6e9947588cdbfe718efe93313en,
          0x258281ddba388ed64cec71a5a7172e820810e911262fc3d58c60101a44967c2fn,
          0x2c7a9eacbc09abc52bd6a6aeceb48817a66922249289c2b26f7a1abdc5cca18cn,
          0x2a04875a74608c64f5f2254ff6b0915fa8ba933e01bba8b811702537b83b97c6n,
          0x224c24a0bdd73daeb174233d13caf8293fc6eef5e6ee6de179efdd6ae1fe11afn,
          0x08cd5ccd7dea1e26d95e9c518fc936e8147c1ce16f2b81dda49a051766ab94d2n,
          0x1acbc785b680a00252980cfff38c66225ba2b243816d0a1cebdbecc5c5acb238n,
          0x2459b8f9f74d81d483ef384f23a3fbc4c2ee078ff936131fe13f300ea8071b0cn,
          0x2c200f2ce53ee47e0009ffbc9642cb7a04ec9b6edec610d29028f3dc9d074f8cn,
          0x276ea1c4cd336ff3d3fbb4b99ef465a8555bcdd404ec8258fed20752db35553en,
          0x14fcb41fd8bf2516431f34a3cf647c1312bac9a0e9bb1f92b6604fc6eb1a6e8en,
        ])
      );

      eql(
        Fp12.sqr(mul),
        Fp12.fromBigTwelve([
          0x17a94f86cafa37b62963f9a8370a3aa9fcc38ef685e0db12748399f0e68e2973n,
          0x2eb4e4014264b7e7757107eb5ec09827f5beb9b036ff9a6a9ccfc8ddad4aa109n,
          0x005157b52aa6be15635bcfa6e2c6cda2439d75a13142160966114ea420bf92e9n,
          0x003490539e85fbf0da4dcc7a2c28fecbe442595a799966011df52b3cecd63029n,
          0x0d94c8b5da7ab1ac1454a2c70f22859f7602fe493356eed64afa14e2cf272f40n,
          0x29e9f0bfc4aebdac0ecb7b1e989aa7fdd9e2e9a6c916a2c661d21b172d568a49n,
          0x026882dcf109ac553636af8fec4dce062f38380923943a1f79b369ea88350a8bn,
          0x1f2f475c683ef42a035f3867655d51d300290da1f087070d6b674d8a0bf46865n,
          0x0fe80db898a528fc5a3878c73bd714ada8d590451a0fd87b4a5668f1a87c36e3n,
          0x077cbec63b49cef60ffb560da27ffbb91917931ec9fc96993b852f73717f9f9cn,
          0x002512b398dc498e945639faddd5055436b43327b58b4dca3fd5777fc32c749en,
          0x29b6713336cc68bbd8e13a86c8b35c4c690cf584fff0ea348ce47c57e1e53c10n,
        ])
      );
      eql(
        Fp12._cyclotomicSquare(mul),
        Fp12.fromBigTwelve([
          0x30023f5698c9c493e21427e352f9f17dd242334f799b74eeafb66650b491496dn,
          0x2177bc1d90e112dc045e3864144b7e73063cd4693af85c1b3bef6116880bc349n,
          0x0546acbe22e9b02552bc46d6914c495a8d4844d3e54a37edc1a139803a5ca1e4n,
          0x0d699ef253da38b3c5731f796629fa945777369362a3dacaadbcbf863b585283n,
          0x1fb1eba7ca2a7b9b947c31847a5a58e221bcc93439499269cdc787e200eb8757n,
          0x2331f15640fa91f07c474366d5e9d60b905d7c75602950e2f9d79d0cd6d7a9c6n,
          0x0eae836ebe215074a7789a9f266ee076c48b100d8621ce599bb28ff9833b745cn,
          0x222db0165b84ec63705c405eac22a834e4abb331aa3509cbf958ff9b92ff78d9n,
          0x03f9a85af227cc827ced6389a38d8004467eaa4a2fb7a9f5f3c675701fd5e334n,
          0x1c8bc2140b9a3b455105eb9a19d7159fa070721cfe0c4eed09e21456a86ca71cn,
          0x10472ed8a8e822c166b7e887aab35f15cc9abb80c11da0ece049f335b1ed6c14n,
          0x1aa102d0bc8d6c3cfebf6670317df90ef6d70e055fecce069451f90157ebfcd9n,
        ])
      );
      eql(
        Fp12._cyclotomicExp(mul, 123n),
        Fp12.fromBigTwelve([
          0x20dd07451a7f327962a99e97afdf8eb9dea808fce04ae0769e354d48e3bcd95fn,
          0x2e98e2a311022b108877fe2d66c889f3667669acc31f31adb1ff15fb285762fcn,
          0x0c373b022ccae876c116bdb3e576a35a801d0df59a1f2351ee7dab9dd58e5e75n,
          0x02b18f89721085314159d934622dd2eec0f58e3a72ffaee3ba9669622ee988a5n,
          0x0c81f192937cc9f4abc89d38ec984c65e93e31c04959ca49fc39ee8a20dde5b8n,
          0x05eafc0203279d01c5bee860bc7793af88b17877b9a58cc21ba5c32d2c7c01a8n,
          0x0e7c1ce823bc6ac14b7f96832b12d15bb556dead8bc72f4a7f3da6bab140a2a3n,
          0x2a65afa46d7bac7d1dd5dadfb55180810518036ec3c4fbf04371791e88402e82n,
          0x0db4e1b4938f7ea77bf88c95c0bfc87c36206c8d823b5886f0e43384a0076560n,
          0x287e79e5e8d198a4eb4bebd1e3b624c60088ab926c581057e43f4191959967ecn,
          0x22f86b6ce9597f60c818a50a6841516864f5386b3c9c9e8f2dcbf9ef88f03fa8n,
          0x305b3e860b6a4988a6d717a1bd0ff611611caea2f4fcd93b96bcfc1adfa88738n,
        ])
      );
      eql(
        Fp12._cyclotomicExp(
          Fp12.fromBigTwelve([
            0xbaf254628469e1f060f4e82859059ce008ea15740f40b92a6f5800845360fc5n,
            0x25a99929fbb953b38e13f612411e9166035a15c42a3303a85ae682661306a7fan,
            0xf9a1b52dc2e883827cbdfe72569407da3b954fec80a65ec8ca37da2b2e964ean,
            0x20792885c810a800f9e2ac5b5cb916dfd935baad61c59069a6b265bdef4f60fn,
            0x2b59f814e7547eb6e3f2e8971ed9fb3b02138e391194b70841559885f520b9d3n,
            0x2ae2c8ef14db3d139f28b1c9e579ff6fba991612244c37becddbb502b58b8c0dn,
            0x2207da6bde85d2bc8bd616e037894b7301a41a0a553a590ef83de377ef19c4e7n,
            0x1eff798c7dd143cccb51e4c67ebbd1dbce071e6e8d340905c053618b2bf437d1n,
            0xed61df076233b9982e7379d11dec023c4411b9614f589d5d7489d971bb5e1f5n,
            0x29c3c191b94682091805da937a8dd7395ea326adcd8e1f97e4c572cdf3c1405n,
            0x1a56198f69acb4a2d8b65382445b266a0037a3d2303670f263ee128c51cd87ddn,
            0x1b1cfc52f445624dc2082421fcc83e5937291d279fbdc1e04bfe40d9bcc468a2n,
          ]),
          4965661367192848881n
        ),
        Fp12.fromBigTwelve([
          0x1e68c703eda1a853536ab80aee7fda13bdcd79ab60d1b16897f564ea8e4e2d3fn,
          0x02fc84e27f9795620001c64d8c19cc8826ec15ff6c9bfddab4cfe596682f2a78n,
          0x04daf74697ad9a9c6065dabc9eae2dc1bd35499f3723db0be30c978f1ca43ed6n,
          0x20ec5395f928dd9c3f533a296f1616c78b627bd1bf4d4cd7954fbe63a0c266d3n,
          0x04f887b90d3f841a2919b8e65f9ac1663086132603aa00f5716e1a3470ff2314n,
          0x1eb6566c771211e84807260bae18e4ec401b5883d7f57d16ffbf9228669b6b48n,
          0x05ee9bad2ebbb1ac7e3d7e0a7349db409c692f1d43e2aeb60723dabfd65aed4an,
          0x166ab9c4954fce04024b486ec6dceeb31e46bea49e852b81d22ac24a3f3f0b64n,
          0x1fe7ae67e587697fd785e304a6781527ae0afb38f0faf84aac71e22ec63f0935n,
          0x26c7d2c37c7af1450ae3f7f6bddc1ff542243788e668623a74dbe8c006619365n,
          0x2a2a4bad4c3cb7775219573db4a5a1a1abcce6e0cd68c013436609db3eac55f2n,
          0x2cf72cbac37c8dee93e34b7f0255fc2171b2439f15cd2153e34b035f5152f01en,
        ])
      );
    });
    should('finalExponentiate', () => {
      const mul = Fp12.fromBigTwelve([
        0x1f7e1915f79c255833f7a13152cbde37e75c7477b0e9e43bd7682159c581eb59n,
        0x0b87ab9f76ec58d51764793075679db7ef021b6e9947588cdbfe718efe93313en,
        0x069cdaf8a1c617a3411205c2f79031bf765e5c223019ea81c7b30b979ae8a7a5n,
        0x284421e203ea9cd11d7e7c3bc4f6c0f6f2f0df6dea4f5f0e77532bf5db230190n,
        0x0cddcd1a97c14c06ac7066d8260433f49341d541de58cc5f0e9b77f2a44b6f75n,
        0x1c0740acf5fbc0dae7b89b70a340dd09535c6358cfcc30dbc8e50081d0766067n,
        0x0cf7e9c5f664bf3c4e805797034b637045be90a2e22dcbdc404d85aa1c4baee8n,
        0x126b7779bce9780813bff1692a361eaf4388727c737f9df8b7f98e4a709e7c96n,
        0x0c0a9578e9e41e5534610d675ddd5c98d49363016f3bb76d5ae15c083075e23bn,
        0x04443f45fbf2bbabb84645f9eb3e8ce39294cf2289abb9baabf7983a3b75adbbn,
        0x1f7797b3b1b3bc1b201b49d1e6d32a3114444f43bcd8cac719fbcef72d861449n,
        0x0aaa7b3a32f45da005612e5f1d642f4c3747672cb6e299260fc8ce90cc5a8a87n,
      ]);
      eql(
        Fp12.finalExponentiate(mul),
        Fp12.fromBigTwelve([
          6877767501181987742927301083772237622289831588906073414192853124854733488141n,
          4386887093521624673170092834166299570144971563640253908019837809947742004372n,
          13640773619431476426520882826276278557630840137337299012891785016611959952430n,
          7268455777017698757211983785306632948737029677513470266761141038276844553489n,
          10100950439432706176610211223982736081029905332425872847154371133885177760665n,
          11938128584263927206051686025736458298330103984196747008513136549730018898044n,
          12056865137184021296809321410231029377560836326023532550808423713060479647372n,
          4028888956608908278532179323564281506837858130734817280228205549071621149376n,
          15835261536611083273496275824883267621593881414758467361905728716783260571466n,
          426667733532217393104068178054333962998217547139013256749962953227098651333n,
          601970024992042425928568530229649914690102826031050225452094986523823885613n,
          2784163803709253222160526895703992712121082107842312647738335157874553587075n,
        ])
      );

      eql(
        Fp12.finalExponentiate(
          Fp12.fromBigTwelve([
            0x1712d92ebcd30192d088d400e73f237b316ff48a966eeb8bc137f9721700c67dn,
            0x0b9d5f0bff82e0831788db1059bef99a96ce464f10c4341ae8e31dd41af7ab5cn,
            0x200d99fa5b4bfef484530754d46e8d94e1fc49bc98d207769c5486333d9025fan,
            0x146235afdc24ffea4edc8c5f51961a17b99452d2d3ca7ca245f0a151d930fd7dn,
            0x1794b532c42b9dcfb227d4c098a43bade5aa22b28e15bb1396881921de513d3dn,
            0x150baf795491d046d239741daefd45a52b2082e6c1e3afb7b6a5386ec2591f2bn,
            0x013573cdc3dff1fcb7c58b409e7b6e1c514b4e850377d84b26c83f4af45a5c5cn,
            0x0e5732085aeebe7e34ba2650047cc52e6388d3529b9e04372349a9db0104873en,
            0x2e1cc5384b311877c3af0dc2486834efcda4f6a4810c59398245073d8ec3162dn,
            0x029116a6e1247f4ed108c9e2257e9da5566a97b3b9ffee4de73acc6faa6a032fn,
            0x264bbcca616ca585d4feec0d55c87af4fbab3738a6472e7df187067a2d402b97n,
            0x1bbd4468feb29ccf9e0135e248e5cd409d17f29ac1d654d792a4fc81bd8c7aa4n,
          ])
        ),
        Fp12.fromBigTwelve([
          13877656491661640631600244169220085891359450949682004465527137460793545938152n,
          3906410751011947226487718801344071125724542809130912622160747522251298167903n,
          14877340337010458596159093350274930378022685114520124604334403250850705261916n,
          15002627621598333987514528663889323947229818387586466768805063641268986091437n,
          9459026593840693758505877383636831468940555440768655768735807862126696543005n,
          839074483341377826715253861431538099863683820551181415205391532434041318178n,
          21369793484557747153505383435386147314242066877688284700608338872262972140437n,
          10359338840505817382931807446029405088966939886815150559845836797422856203584n,
          21667451766603044459224145600140536868490650420412059410045651687544062321731n,
          16665881988310663593326798056095459790150529177068241564202294422570163645490n,
          8672190577268353850464353328235419709386222533197452878226076881401949666512n,
          17766332416336874386911842842950545082144722270093565065560359187820441614652n,
        ])
      );
      eql(
        Fp12.finalExponentiate(
          Fp12.fromBigTwelve([
            0x24ea9b007d638d0501e6388ba9de0440270dafa311387968d5b327dd75b72ff9n,
            0x21e7bd21c7b72836eec1b46cb198851f714b65ce4bd50267f6f6401300f19909n,
            0x1517179404ac2ef0b3a3d41166d4af2fdcaa11dcb829f260a04a216052bb42b4n,
            0x0552ff39779791ac79e8d4b0945d85eb7dfc3e9f5f9c60b91d395226334d7e6dn,
            0x1b4f76bc8f9491ac69a02912c91460ee7d511e8c53aca3ee93e25d7887f3d1ben,
            0x065d467462be3cc3feb7f10c6c29e74f2e7c77f7a603eeaaf8ec3a62cd7905cen,
            0x23d82ad8b0cb90a7f312821e8aa42e07ceae37b69167c64081f67ec82eedde12n,
            0x0456eaab01f06cd437f624b0438ff916a49021691e3aa634d238469173ee0680n,
            0x216b7cb771d26d3a856a0b89c43d8dd47d28dd25b3333bbd9c12717ecd67316dn,
            0x007bed4865c80923b9705f3702d53aa58e092b9e101c889421e1f79f32027830n,
            0x07df3f2045b7b0f6af56568eb2d75103cbfc86fd45cd67c5f3a96becba1eeeb8n,
            0x2f825c3379e24d1c8f2cac1a05aee4aea19117aa4f99ccfc2c0d0dcb0ed15679n,
          ])
        ),
        Fp12.fromBigTwelve([
          0x10a05870140ee692dd305bcbf2d28643ad4c414a286b5a834b33d8332323e105n,
          0x2ccdf3b05ac2943c1747bafcc9cf3ddb87a5756db0db55cf0a7dc5739c22e71an,
          0x1a671391a953bebca7a7aff94b940ce2adc3cc80abcf7c7dc6a31fbfcc97184an,
          0x01adf35dd96db7c503157789178e00084e091c750539fb57cf665e63eaec7564n,
          0x2379944391f74a7d4edcb25aee4192c9677bcb9e658683c0b5b6d3634d0d9f24n,
          0x0a6cf3260f092cdb5272a05264425a772f45cd460c700b89aabd8a900c9b0056n,
          0x20f23431442069b6de7c7dad7da6dd01bb990e2fe3363879ea76d8e80063ea92n,
          0x188687e3b1e36d94f139768023743f5735b1cd5278767cd9c1c558ca917f315fn,
          0x2791d0db6debecd92ba89a372f2b306904bd835e414e67ae53c62eaf8ef89111n,
          0x02f8f859de46e23d8ed4b157166b9c76b6ea07d27acbac3267a8eca0cedb4fban,
          0x1897e70be8b1eb36f9997fe9765aade4bb0cb7417e1cb3d70baef876df9a3786n,
          0x269641f22b7c4f45af618334e3e15fcd4d4844df38d65c376b0db53a13b02ffan,
        ])
      );
    });
    should('Sparse multiplication', () => {
      // Sparse
      const f12m = Fp12.fromBigTwelve([
        14244494172137254969594643025187612313596583059399776446481360252038625225561n,
        5215150185941911353875535033815039681144663555998205467685043428415199457598n,
        2991016517412169500482498383362259827931066279549795810865130292524517730213n,
        18212893394725427420575531605813081161158126844548795047715546640841015755152n,
        5819642959256598814835908610622345327220464701403874765564090486377264410485n,
        12677574064567005686715477910262120331674205539230276718926527915059817373799n,
        5865778851956021888040979092166391095940164139955832742877905197518788734696n,
        8331508500293651273722467052195914577024062031472658190584791222569070918806n,
        5446454273677858817377266617713738799931386348975063416494446574534028288571n,
        1929833691527403336660572823008671344950034771340781511225281447839734803899n,
        14233000115032918798785952246007985270659932100988995610419881744204174857289n,
        4824342970688691964976119141257507032105805643608313922359860622298332170887n,
      ]);
      const f2 = {
        c0: 14915367931151687313527782314310395056617474070176176799315072532155545111131n,
        c1: 21234748560869198098271980834340238051100753263426135951820710752881888827685n,
      };
      eql(
        Fp12.mul014(f12m, f2, f2, f2),
        Fp12.fromBigTwelve([
          8922703303827390308271996316386725983337485634407752198681990540008924199346n,
          1857839433437893569026170876625659993601503502163219580966087474210929482827n,
          14214408803873669949136526754234216947933984034479939216626656350936422213383n,
          354546224159683095374822269302950156682669145509395665940996482003922767024n,
          7896139838712081128944689523043845476914864079674514013337382553150953481545n,
          936466525623770132523754913994805471293907132513889849326794926625780524046n,
          137127705665011878472112784797322859395964252527832357689870296504819831890n,
          5081276118310367284684262033949674028914403947006545645168455549369868538578n,
          9388849546355707406167437099119694196463419969978917025100953758580375957746n,
          6400723868037807945056319552496950072296145864120337930745411800012012445606n,
          117417194481717453412510690260404644532097922128577850506936159224479167738n,
          16042725332896518878477474934414199844982931081285372762536244621942182235661n,
        ])
      );
      eql(
        Fp12.mul034(f12m, f2, f2, f2),
        Fp12.fromBigTwelve([
          18199611857384505633306727528588064043948891556974835246992059784383667355653n,
          9104008595071614788893864646852378151854504584376465857887640406461486884046n,
          89953050391170532054293125915883512791764755658179333207527854073847511178n,
          17968314303321981214164984888721565897471200012019650962356943817405824292191n,
          16913809120856148547636902714158034990710236329757818689349215165720939689680n,
          10753529250436849467892536771667890310993674590744250311397935222454679471605n,
          418354919485481333893043566886944029272247216765265373571463588441362070323n,
          5584865830052389902453220585309248452735893498174695814174821130792383953017n,
          13907994877186780696376189074265629054513750865126507819846077276700692944499n,
          15812477972350655140356633211521208706686231586539615168279072113618220066977n,
          8230017909489517303063244767356954502075430415498343927417369932537314406989n,
          5441188678846610974100839762726455957498386918047215809857057994193067376146n,
        ])
      );
    });
  });

  should(`Basic`, () => {
    // Verified with py_ecc

    // Ok, this seems correct?
    const g1 =
      bn254.G1.Point.BASE.multiply(
        18097487326282793650237947474982649264364522469319914492172746413872781676n
      );
    g1.assertValidity();
    eql(g1.toAffine(), {
      x: 0x16f7535f91f50bb2227f483b54850a63b38206f28e0a1a65c83d0c90762442a9n,
      y: 0x0b46dd0c40725b6b4a298576629d77b41a545060adb4358eabec939e80691a05n,
    });
    const g2 =
      bn254.G2.Point.BASE.multiply(
        20390255904278144451778773028944684152769293537511418234311120800877067946n
      );
    g2.assertValidity();
    eql(g2.toAffine(), {
      x: {
        c0: 0x1ecfd2dff2aad18798b64bdb0c2b50c9d73e6c05619e04cbf5b448fd98726880n,
        c1: 0x0e16c8d96362720af0916592be1b839a26f5e6b710f3ede0d8840d9a70eaf97fn,
      },
      y: {
        c0: 0x2aa778acda9e7d4925c60ad84c12fb3b4f2b9539d5699934b0e6fdd10cc2c0e1n,
        c1: 0x1e8f2c1f441fed039bb46d6bfb91236cf7ba240c75080cedbe40e049c46b26ben,
      },
    });

    eql(
      bn254.pairing(g1, g2, true),
      Fp12.fromBigTwelve([
        7520311483001723614143802378045727372643587653754534704390832890681688842501n,
        20265650864814324826731498061022229653175757397078253377158157137251452249882n,
        11942254371042183455193243679791334797733902728447312943687767053513298221130n,
        759657045325139626991751731924144629256296901790485373000297868065176843620n,
        16045761475400271697821392803010234478356356448940805056528536884493606035236n,
        4715626119252431692316067698189337228571577552724976915822652894333558784086n,
        14901948363362882981706797068611719724999331551064314004234728272909570402962n,
        11093203747077241090565767003969726435272313921345853819385060670210834379103n,
        17897835398184801202802503586172351707502775171934235751219763553166796820753n,
        1344517825169318161285758374052722008806261739116142912817807653057880346554n,
        11123896897251094532909582772961906225000817992624500900708432321664085800838n,
        17453370448280081813275586256976217762629631160552329276585874071364454854650n,
      ])
    );
  });
  should('Cross-tests', () => {
    // verify that we work exactly same as:
    // - https://github.com/paritytech/bn (old version)
    // - https://github.com/zcash-hackworks/bn
    // - https://github.com/arkworks-rs/curves/blob/master/bn254/src/lib.rs
    const crossTests = jsonGZ(CROSS_PATH_GZ);
    for (const [name, vectors] of Object.entries(crossTests)) {
      if (['ark_bls12-381', 'ark_bls12-377'].includes(name)) continue;
      const { Fp, Fp2, Fp12 } = bn254.fields;
      // should(`${name}`, () => {
      for (const t of vectors) {
        // TODO: projective stuff is somewhat broken on export?
        const g1 = bn254.G1.Point.fromAffine({
          x: Fp.create(BigInt(t.g1.x[0])),
          y: Fp.create(BigInt(t.g1.y[0])),
        });
        const g2 = bn254.G2.Point.fromAffine({
          x: Fp2.fromBigTuple(t.g2.x.map(BigInt)),
          y: Fp2.fromBigTuple(t.g2.y.map(BigInt)),
        });
        const fp12 = Fp12.fromBigTwelve(t.pairing.map(BigInt));
        const p = bn254.pairing(g1, g2, true);
        eql(p, fp12, name);
      }
      // });
    }
  });

  describe('ETH', () => {
    /*
    @ethereumjs/evm depends on rustbn-wasm which is wasm for https://github.com/ewasm/ethereum-bn128.rs
    */
    const fixHex = (hex2) => {
      if (hex2.startsWith('0x')) hex2 = hex2.slice(2);
      return hex2;
    };
    const ethNum = (hex) => {
      return bytesToNumberBE(hexToBytes(hex));
    };
    // Eth input data is zero extended tape with infinity size. Except for cases when it is not (pairing). Eth is awesome and totally makes sense!
    const ethNums = (input, count) => {
      input = fixHex(input);
      if (!input) return new Array(count).fill(0n);
      // pad to 64 chars
      if (input.length % 64 !== 0) input += '0'.repeat(64 - (input.length % 64));
      const res = Array.from(input.match(/.{1,64}/g)).map(ethNum);
      while (res.length < count) res.push(0n);
      return res;
    };

    const ethAdd = (input, output) => {
      const [Cx, Cy] = ethNums(output, 2);
      let res;
      const [Ax, Ay, Bx, By] = ethNums(input, 4);
      try {
        let A = bn254.G1.Point.fromAffine({ x: Ax, y: Ay });
        let B = bn254.G1.Point.fromAffine({ x: Bx, y: By });
        A = A.add(B);
        A.assertValidity();
        res = A.toAffine();
      } catch (e) {
        res = { x: 0n, y: 0n };
      }
      eql(res, { x: Cx, y: Cy });
    };
    const ethMul = (input, output) => {
      const [Cx, Cy] = ethNums(output, 2);
      const [Ax, Ay, scalar] = ethNums(input, 3);
      let res;
      try {
        let A = bn254.G1.Point.fromAffine({ x: Ax, y: Ay });
        A = A.multiply(scalar % bn254.G1.Point.Fn.ORDER);
        A.assertValidity();
        res = A.toAffine();
      } catch (e) {
        res = { x: 0n, y: 0n };
      }
      eql(res, { x: Cx, y: Cy });
    };
    const ethPairing = (input, output) => {
      input = fixHex(input);
      const { Fp, Fp2 } = bn254.fields;
      const { G1, G2 } = bn254;
      let f = Fp12.ONE;
      const [out] = ethNums(output, 1);
      const elements = Math.ceil(input.length / 64);
      const p = ethNums(input, elements);
      try {
        if (elements % 6 !== 0) throw new Error('error');
        let pairs = [];

        for (let i = 0; i < p.length; i += 6) {
          const Ax = p[i];
          const Ay = p[i + 1];
          const Bay = p[i + 2];
          const Bax = p[i + 3];
          const Bby = p[i + 4];
          const Bbx = p[i + 5];
          // Bigger than module coefficients
          for (const i of [Ax, Ay, Bay, Bby, Bbx])
            if (Fp.create(i) !== i) throw new Error('failed');
          const A =
            Fp.is0(Ax) && Fp.is0(Ay) ? G1.Point.ZERO : G1.Point.fromAffine({ x: Ax, y: Ay });

          const ba = Fp2.fromBigTuple([Bax, Bay]);
          const bb = Fp2.fromBigTuple([Bbx, Bby]);
          const B =
            Fp2.is0(ba) && Fp2.is0(bb)
              ? G2.Point.ZERO
              : G2.Point.fromAffine({
                  x: ba,
                  y: bb,
                });
          A.assertValidity();
          B.assertValidity();
          // zero is just skipped (was set to Fp12.ONE before)
          if (A.is0() || B.is0()) continue;
          pairs.push({ g1: A, g2: B });
        }
        f = bn254.pairingBatch(pairs);
      } catch (e) {
        f = Fp12.ZERO;
      }
      const res = Fp12.eql(f, Fp12.ONE) ? 1n : 0n;
      eql(res, out);
    };

    should('add', () => {
      const input =
        '0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002';
      const output =
        '030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4';
      ethAdd(input, output);
    });
    should('mul', () => {
      const input =
        '000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000042';
      const output =
        '12e017e752e718f7d1750138f3fd97d930073164499793d9b5405a9ff30e765a11d73265f2f8035c1eb99695a20bc0e550afbc7d506f9f1a1ffcb9f0ade01454';
      ethMul(input, output);
    });
    should('pairing', () => {
      const vectors = [
        {
          input:
            '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa',
          output: '0000000000000000000000000000000000000000000000000000000000000001',
        },
        {
          input:
            '1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa',
          output: '0000000000000000000000000000000000000000000000000000000000000000',
        },
        {
          input:
            '1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550',
          output: '0000000000000000000000000000000000000000000000000000000000000000',
        },
      ];
      for (const { input, output } of vectors) ethPairing(input, output);
    });
    should('sedaprotocol', () => {
      for (const t of seda.add) {
        const Ax = BigInt(`0x${t.x1}`);
        const Ay = BigInt(`0x${t.y1}`);
        const Bx = BigInt(`0x${t.x2}`);
        const By = BigInt(`0x${t.y2}`);
        const Cx = BigInt(`0x${t.result.slice(0, 64)}`);
        const Cy = BigInt(`0x${t.result.slice(64)}`);
        const A = bn254.G1.Point.fromAffine({ x: Ax, y: Ay });
        const B = bn254.G1.Point.fromAffine({ x: Bx, y: By });
        eql(A.add(B).toAffine(), { x: Cx, y: Cy });
      }
      for (const t of seda.mul) {
        const Ax = BigInt(`0x${t.x}`);
        const Ay = BigInt(`0x${t.y}`);
        const scalar = BigInt(`0x${t.scalar}`) % bn254.G1.Point.Fn.ORDER;
        const Cx = BigInt(`0x${t.result.slice(0, 64)}`);
        const Cy = BigInt(`0x${t.result.slice(64)}`);
        const A = bn254.G1.Point.fromAffine({ x: Ax, y: Ay });
        eql(A.multiply(scalar).toAffine(), { x: Cx, y: Cy });
      }
    });
    describe('eth dump', () => {
      should('EC_ADD', () => {
        for (const [input, output] of ethDump.NOBLE_DUMP_EC_ADD) ethAdd(input, output);
      });
      should('EC_MUL', () => {
        for (const [input, output] of ethDump.NOBLE_DUMP_EC_MUL) ethMul(input, output);
      });
      should('EC_PAIRING', () => {
        for (const [input, output] of ethDump.NOBLE_DUMP_EC_PAIRING) ethPairing(input, output);
      });
    });
  });
});

should.runWhen(import.meta.url);
